local EffectEmitter = class("EffectEmitter",function() return cc.Node:create() end)

local LocationConfig = import(".BattleLocation")

local math_atan2 = math.atan2
local math_random = math.random
local math_between = math.between
local math_abs = math.abs
local math_clamp = math.clamp
local math_bezierat = math.bezierat
local math_bezieratTangent = math.bezieratTangent
local math_floor = math.floor

local CCNode_setPosition = cc.Node.setPosition
local CCNode_toLocalPosition = cc.Node.toLocalPosition

function EffectEmitter.create(params)
	local instance =  EffectEmitter.new()

	for k,v in pairs(params) do
		instance[k]=v
	end

    if instance.displayNode then
        instance:addChild(instance.displayNode)
    end

	instance:initData()
    return instance
end

function EffectEmitter:ctor()
    self.beenFire = false

    self.mIsShouldRemove = false
end

function EffectEmitter:initData()
	--是否是点目标
	self.isTargetPoint = self.targetPoint ~= nil
	if self.isCurve then
		if self.curvedRandomIndex > 0 then
			--print("===========self.curvedRandomIndex:",self.curvedRandomIndex)
			local params = Res.CurvedRandomConfig[self.curvedRandomIndex]
			self.xParam1 = math_random(params.x1RandMin,params.x1RandMax)/100
			self.xParam2 = math_random(params.x2RandMin,params.x2RandMax)/100
			self.yParam1 = math_random(params.y1RandMin,params.y1RandMax)/100
			self.yParam2 = math_random(params.y2RandMin,params.y2RandMax)/100

			self.isSlow = params.isSlow
		else
			--print("===========self.curvedFixedIndex:",self.curvedFixedIndex)
			if self.curvedFixedIndex <= 0 then
				self.curvedFixedIndex = 1
			end
			local params = Res.CurvedFixedConfig[self.curvedFixedIndex]

			self.xParam1 = params.x1/100
			self.xParam2 = params.x2/100
			self.yParam1 = params.y1/100
			self.yParam2 = params.y2/100

			self.isSlow = params.isSlow
		end
	end
end

function EffectEmitter:isBeenFire()
    return self.beenFire
end

function EffectEmitter:setIsGuideSkillEffect(b)
	self.isGuideSkillEffect = b
end

function EffectEmitter:forceFire()
	self:fire()
end

function EffectEmitter:pause()
	getmetatable(self).pause(self)
	local displayNode = self.displayNode
	if displayNode then
		displayNode:pause()
	end
end

function EffectEmitter:resume()
	getmetatable(self).resume(self)
	local displayNode = self.displayNode
	if displayNode then
		displayNode:resume()
	end
end

function EffectEmitter:remove()
	local displayNode = self.displayNode
	if displayNode then
		displayNode:stopAllActions()
		self.displayNode = nil
	end
	self:removeFromParent()
end

function EffectEmitter:getPos(node, type, bone)
	local posX, posY = 0, 0
 	if bone and node.getBonePos then
        posX, posY = node:getBonePos(bone)
        if type == 4 and bone == "body" then
        	posX, posY = node:getHitPos()
    	end
    elseif iskindof(node, "Actor") and (type == 1 or type == 2) then
    	local armaturePosX, armaturePosY = node:getArmature():getPosition()
        posX, posY = node:toWorldPosition(armaturePosX, armaturePosY)
	elseif type == 5 then
		local nPosX,nPosY = node:getPosition()
		local wposX,wposY = node:getParent():toWorldPosition(nPosX,nPosY)
		posX = wposX
		posY = self.startPosY
    elseif type == 7 then
    	local x = LocationConfig:getPosOnEntityLayer(LocationConfig:getLogicCenterPos())
    	if not x then
    		x = display.width/2.0
    	end

        posX,posY = self.relativeNode:toWorldPosition(x,0)
        -- pos.y = display.cy
    else
    	local nPosX,nPosY = node:getPosition()
        local wposX,wposY = node:getParent():toWorldPosition(nPosX,nPosY)
        posX = wposX
        posY = wposY
    end
    return posX,posY
end

function EffectEmitter:getFromPos()
	local fromNode = self.fromNode
	local fromBindtype = self.fromBindtype
	local fromBone = self.fromBone
	return self:getPos(fromNode,fromBindtype,fromBone)
end

function EffectEmitter:getToPos()
	local targetPoint = self.targetPoint
	local toBindtype = self.toBindtype
	if targetPoint then
		local posX,posY = self.relativeNode:toWorldPosition(targetPoint,0)
		if toBindtype == 5 then
			posY = self.startPosY
		end
		return posX,posY
	else
		local toNode = self.toNode

		if (not toNode) or tolua.isnull(toNode) then
			return self.endPosX, self.endPosY
		end

		local toBone = self.toBone
		return self:getPos(toNode,toBindtype,toBone)
	end
end

function EffectEmitter:isPlaying(name)
	return self.displayNode and self.displayNode:isPlaying(name)
end

function EffectEmitter:isPlayingAni(name)
    return self:isPlaying(name)
end

function EffectEmitter:playAni(name)
	local isAniPlaying = self:isPlayingAni(name)
	if isAniPlaying then
		return
	end
	local params = {name = name}
    if params then
        params.fadeInTime = 0

        return self.displayNode:playAni({name = name})
    else
        self.displayNode:play()
        return true
    end
end

function EffectEmitter:setAccumulator(accumulator)
	self.accumulator = accumulator
end

function EffectEmitter:getAccumulator()
	return self.accumulator
end

function EffectEmitter:fire(entityPosX, isRestFromPos)
	self.startPosX = 0
	self.startPosY = 0

	local displayNode = self.displayNode
	local isArmature = iskindof(displayNode,"Armature")

	local actions = {}

	local fromNode = self.fromNode
	local toNode = self.toNode
	local targetPoint = self.targetPoint

	local fromPosX,fromPosY = 0,0
	if fromNode then
		if isRestFromPos then
			fromPosX,fromPosY = self:getFromPos()
			self.startPosX = fromPosX
			self.startPosY = fromPosY
		else
			self.startPosX = entityPosX
        	local _,posY = displayNode:toWorldPosition(0,0)
			self.startPosY = posY
		end

		self.endPosX = self.startPosX
		self.endPosY = self.startPosY
	end
	if fromNode and (toNode or targetPoint) then
		local toPosX,toPosY = self:getToPos()
		self.endPosX = toPosX
		self.endPosY = toPosY
		local moveAni = self.moveAni
	    if moveAni and isArmature and displayNode:getAnimation():hasAnimation(moveAni) then
        	displayNode:playAni({name=moveAni,fadeInTime=0})
        end

        if math_abs(self.endPosX - self.startPosX) < 100 then
            displayNode:setVisible(false)
        else
            displayNode:setVisible(true)
        end
	end

 	local newPosX,newPosY = CCNode_toLocalPosition(displayNode:getParent(),self.startPosX,self.startPosY)
 	CCNode_setPosition(displayNode,newPosX,newPosY)
	displayNode:setRotation(0)
	self.beenFire = true

	self.firstEndPosX = self.endPosX
	self.firstEndPosY = self.endPosY
	self.offsetX = self.startPosX - entityPosX
end

function EffectEmitter:setInsideDeceased(deceased)
	self.insideDeceased = deceased
end

function EffectEmitter:setDeceased(deceased)
	self.deceased = deceased
	if deceased then
		if self.displayNode then
			local isVisible = not deceased
			if isVisible then
				self.displayNode:setVisible(isVisible)
			end
		end
	end
end

function EffectEmitter:hideSelf()
	local time = 0.05
	local displayNode = self.displayNode
	if displayNode then
		local hasAction = displayNode:getActionByTag(Enums.CommonActionTag.BattleProjectileHideAction)
		if hasAction then
			return
		end

		local actions = {}
		table.insert(actions, cc.DelayTime:create(time))
		table.insert(actions, cc.CallFunc:create(function() 
			displayNode:setVisible(false)
		end))
		local action = cc.Sequence:create(actions)
		action:setTag(Enums.CommonActionTag.BattleProjectileHideAction)
		displayNode:runAction(action)
	end
end

function EffectEmitter:update(posX)
	----------------------------使用 cocos api 计算---------------
	-- local targetVector = cc.pSub(self.startPos,self.endPos)
	-- local normalizedTargetVector = cc.pNormalize(targetVector)
	-- print("--------normalizedTargetVector.x",normalizedTargetVector.x)
	-- -- local moveX = self.startPosX - posX
	-- local moveX = self.startPosX - posX
	-- local y = self.startPosY
	-- print("--------self.startPosX",self.startPosX)
	-- print("--------self.startPosY",self.startPosY)
	-- print("--------self.endPosX",self.endPosX)
	-- print("--------self.endPosY",self.endPosY)

	-- print("--------normalizedTargetVector.x",normalizedTargetVector.x)
	-- print("--------normalizedTargetVector.y",normalizedTargetVector.y)
	-- if normalizedTargetVector.x == 0 then

	-- else
	-- 	local factor = moveX/normalizedTargetVector.x
	-- 	print("--------factor:",factor)
	-- 	y = self.startPosY - normalizedTargetVector.y * factor
	-- 	print("--------y:",y)
	-- end
	--------------------------------------------------------------

	-----------------------手动计算-----------------------------------
	--根据出手时，出手点和结束点，以及子弹逻辑x位置，计算子弹位置

	--子弹逻辑为到达出手点之前，隐藏子弹
	--[[
		if self.deceased then
			self:setVisible(false)
		else
			if posX < self.startPosX then
				self:setVisible(false)
			else
				self:setVisible(true)
			end
		end	
	]]
	
	--子弹逻辑为到达出手点之前，子弹在出手点不动
	--[[
		if posX < self.startPosX then
			posX = self.startPosX
		end
	]]
	

	-- local y = 0
	-- if self.endPosX == self.startPosX then
	-- 	y = self.endPosY
	-- else
	-- 	y = (posX - self.startPosX)*(self.endPosY - self.startPosY)/(self.endPosX - self.startPosX) + self.startPosY
	-- end


	-- local pos = self.displayNode:getParent():convertToNodeSpace(cc.p(posX,y))
	-- self.displayNode:setPosition(pos)
	------------------------------------------------------------------

	------------------------修正子弹方案-----------------------------
	-- if self.deceased then
	-- 	return
	-- end
	if self.insideDeceased then
		return
	end

	local fromNode = self.fromNode
	local toNode = self.toNode
	local targetPoint = self.targetPoint
	local isMove = false
	local displayNode = self.displayNode
	if fromNode and (toNode or targetPoint) then
		isMove = true
	end

	local startPosX = self.startPosX
	local startPosY = self.startPosY
	local firstEndPosX = self.firstEndPosX
	local firstEndPosY = self.firstEndPosY

	if isMove then
		local currentX = self.offsetX + posX --修正x坐标

		--实时计算目标点
		local endPosX,endPosY = self:getToPos()
		-- local endPos = toPos

		local lastTargetX = self.endPosX

		self.endPosX = endPosX
		self.endPosY = endPosY

		local currentTargetX = self.endPosX
		
		-- local oldPos
		local oldPosX,oldPosY = displayNode:getPosition()
        local lastX,_ = displayNode:toWorldPosition(0,0)

		--判断碰撞
		local insideDeceased = false
		if self.deceased then
			insideDeceased = true
			currentX = currentTargetX
		else
			if math_between(currentTargetX, lastX, currentX) 
			or math_between(lastTargetX, lastX, currentX) 
			or math_between(currentX, lastTargetX, currentTargetX)
			or math_between(lastX, lastTargetX, currentTargetX) then
				insideDeceased = true
				currentX = currentTargetX
			end
		end

		local y = 0
		local x = currentX

		local xa = 0
		local xb = 0
		local xc = 0
		local xd = 0

		local ya = 0
		local yb = 0
		local yc = 0
		local yd = 0
		local time = 0
		
		if endPosX == startPosX then
			x = endPosX
			y = endPosY
		else
			-- if self.isCurve and math_abs(currentX - currentTargetX) > 25 then
			if self.isCurve then
				--如果是曲线
				-- local g = 8000
				-- local temp = speed*1000*LocationConfig:getSpace()*display.width
				-- print("temp:",temp)
				-- local screenSpeed = math.floor(temp)
				-- print("-------------screenSpeed:",screenSpeed)
				-- local h = math.pow(self.endPosX - self.startPosX,2)*g/(8*math.pow(screenSpeed,2))
				-- print("-------------h:",h)

				-- local xParam1 = 0.5
				-- local xParam2 = 0.6

				-- local yParam1 = 500
				-- local yParam2 = -200

				
				-- local xParam1 = math_random(1,100)/100
				-- local xParam2 = math_random(1,100)/100
				-- local yParam1 = math_random(-200,500)
				-- local yParam2 = math_random(-200,500)
				
				local totalX = firstEndPosX - startPosX
				xa = 0
				xb = 0 + totalX * self.xParam1
				xc = 0 + totalX * self.xParam2
				xd = endPosX - startPosX

				ya = 0
				yb = 0 + (firstEndPosY - startPosY) * 0.5 + math_clamp(math_abs(xd)*self.yParam1, -150, 500)
				yc = 0 + (firstEndPosY - startPosY) * 0.5 + math_clamp(math_abs(xd)*self.yParam2, -150, 500)
				yd = endPosY - startPosY

				--print("xa:",xa)
				--print("xb:",xb)
				--print("xc:",xc)
				--print("xd:",xd)

				--print("ya:",ya)
				--print("yb:",yb)
				--print("yc:",yc)
				--print("yd:",yd)

				time = (currentX - startPosX)/(xd)
				--print("currentX:",currentX)
				--print("self.startPosX:",self.startPosX)
				
				--print("====app time:",app:getTime())
				--print("====time:",time)
				--时间做个曲线，以达到前慢后快的效果 y=x^2
				if self.isSlow then
					time = time*time
				end 

				--强制到达目标位置 暂时不使用该方案效果还可以，如有需要，可以打开
				-- if insideDeceased then
				-- 	time = 1
				-- end
				
				x = math_bezierat(xa, xb, xc, xd, time)
				y = math_bezierat(ya, yb, yc, yd, time)

				x = startPosX + x
				y = startPosY + y
				-- print("x:",x)
				-- print("y:",y)

			else
				--如果是直线
				y = (currentX - startPosX)*(endPosY - startPosY)/(endPosX - startPosX) + startPosY
			end
		end

		local newPosX,newPosY = CCNode_toLocalPosition(displayNode:getParent(),x,y)
		CCNode_setPosition(displayNode,newPosX,newPosY)

		--设置角度
		if self.autoHeadon and (not self.insideDeceased) then
			-- print("---------self.autoHeadon:",self.autoHeadon)
			local initAngle = 0
			

			if self.isCurve then
				--点的位置不一样才需要旋转
				--浮点数有偏差
			--[[
				if math_abs(oldPosX - newPosX) >= 1 then
					if math_floor(oldPosX) > math_floor(newPosX) then
						initAngle = 180
					end
					--如果需要一直对准目标
					local pSubX = math_floor(newPosX) - math_floor(oldPosX)
					local pSubY = math_floor(newPosY) - math_floor(oldPosY)
					local r = math_atan2(pSubY, pSubX)
					-- print("-----self.autoHeadon----r:",r)
					-- local d = -math.deg(r)
					local d = -r*57.29577951
					-- print("-----self.autoHeadon----d:",d)
					-- print("==========initAngle:",initAngle)
					d = d + initAngle
					print("oldPos",oldPosX,oldPosY,"newPos",newPosX, newPosY,"-----setRotation:",d)
					displayNode:setRotation(d)
				end
				--]]
				--换成贝塞尔曲线切线方法求偏移
				if startPosX < endPosX then
					initAngle = 0
				else
					initAngle = 180
				end
				local pTangentX = math_bezieratTangent(xa, xb, xc, xd, time)
				local pTangentY = math_bezieratTangent(ya, yb, yc, yd, time)
				local r = math_atan2(pTangentY, pTangentX)
				local d = -r*57.29577951
				d = d + initAngle
				--print("-----setRotation:",d)
				displayNode:setRotation(d)
			else
				if startPosX < endPosX then
			        initAngle = 0
			    else
			        initAngle = 180
			    end

			    local pSubX = endPosX - startPosX
				local pSubY = endPosY - startPosY
				local r = math_atan2(pSubY, pSubX)
				local d = -r*57.29577951
				-- print("=========initAngle:",initAngle)
				d = d + initAngle
				displayNode:setRotation(d)
			end
		end

		-- print("currentTargetX:",currentTargetX)
		-- print("lastX:",lastX)
		-- print("currentX:",currentX)

		-- print("lastTargetX:",lastTargetX)
		-- print("currentTargetX:",currentTargetX)
		
		if insideDeceased then
			self:setInsideDeceased(true)
		end
		local newPosX,newPosY = CCNode_toLocalPosition(displayNode:getParent(),x,y)
		CCNode_setPosition(displayNode,newPosX,newPosY)
	end

	if self.insideDeceased then
		self:hideSelf()
	end
	
end 

function EffectEmitter:setShouldRemove(b)
    self.mIsShouldRemove = b
end

function EffectEmitter:isShouldRemove()
    return self.mIsShouldRemove
end

function EffectEmitter:doDelayRemove(k, callBack)
	local action = self:getActionByTag(Enums.CommonActionTag.BattleProjectileRemoveAction)
	if not action then
		local actions = {}
		table.insert(actions, cc.DelayTime:create(0.2))
		table.insert(actions, cc.CallFunc:create(function() 
			callBack(k) 
		end))
		local action = cc.Sequence:create(actions)
		action:setTag(Enums.CommonActionTag.BattleProjectileRemoveAction)
		self:runAction(action)

		--如果逻辑层已经不存在弹道了，需要把弹道设置到 最终目标点
		self:setDeceased(true)
		if self.endPosX ~= nil and self.offsetX ~= nil then
			self:update(self.endPosX - self.offsetX)
		end
	end
end

function EffectEmitter:bounceSetting(fromNode ,fromBone,fromBindtype, toNode ,toBone, toBindtype)
	if self.displayNode then
		self.displayNode:setVisible(true)
		self.displayNode:setScaleX(-self.displayNode:getScaleX())
		self.displayNode:stopActionByTag(Enums.CommonActionTag.BattleProjectileHideAction)
	end
	self:stopActionByTag(Enums.CommonActionTag.BattleProjectileRemoveAction)

	self.mIsShouldRemove = false
	self.insideDeceased = false
	self.deceased = false
	self.offsetX = 0
	
	self.fromNode = fromNode
	self.fromBone = fromBone
	self.fromBindtype = fromBindtype

	self.toNode = toNode
	self.toBone = toBone
	self.toBindtype = toBindtype
end

return EffectEmitter